﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace TvdP
{
    public static class Adapter
    {
        static void AdapterException(bool condition, string msg)
        { if (condition) throw new ArgumentException(msg, "adapter"); }

        internal static Delegate VerifiedThatRequiredSignatureIsMatched(Delegate adapter)
        {
            if (adapter == null)
                throw new ArgumentNullException("adapter");

            var method = adapter.Method;
            var returnType = method.ReturnType;

            AdapterException(returnType == null || returnType == typeof(void),"Adapter must have a return value.");
            AdapterException(returnType.IsValueType, "Return value of adapter can not be a value type.");

            var parameters = method.GetParameters();

            AdapterException(parameters == null || parameters.Length == 0, "Adapter must take at least one parameter.");
            AdapterException(parameters.Any(prm => prm.ParameterType.IsByRef), "Parameters of adapter can not be passed by reference.");
            AdapterException(parameters.Any(prm => prm.ParameterType.IsValueType), "Parameters of adapter can not take a value type.");

            AdapterException(parameters.Any(prm => returnType.IsAssignableFrom(prm.ParameterType)), "Return value is assignable from one or more parameter types.");

            return adapter;
        }

        public static Delegate FromDelegate(Delegate adapter)
        {
            return VerifiedThatRequiredSignatureIsMatched(adapter);
        }

        public static Delegate FromFunc<TFrom, TTo>(Func<TFrom, TTo> adapter)
            where TTo : class
            where TFrom : class
        {
            return VerifiedThatRequiredSignatureIsMatched(adapter);
        }


        public static Delegate FromFunc<TFrom1, TFrom2, TTo>(Func<TFrom1, TFrom2, TTo> adapter)
            where TTo : class
            where TFrom1 : class
            where TFrom2 : class
        {
            return VerifiedThatRequiredSignatureIsMatched(adapter);
        }

        public static Delegate FromFunc<TFrom1, TFrom2, TFrom3, TTo>(Func<TFrom1, TFrom2, TFrom3, TTo> adapter)
            where TTo : class
            where TFrom1 : class
            where TFrom2 : class
            where TFrom3 : class
        {
            return FromDelegate(adapter);
        }

        public static Delegate FromFunc<TFrom1, TFrom2, TFrom3, TFrom4, TTo>(Func<TFrom1, TFrom2, TFrom3, TFrom4, TTo> adapter)
            where TTo : class
            where TFrom1 : class
            where TFrom2 : class
            where TFrom3 : class
            where TFrom4 : class
        {
            return VerifiedThatRequiredSignatureIsMatched(adapter);
        }

        public static Delegate FromFunc<TFrom1, TFrom2, TFrom3, TFrom4, TFrom5, TTo>(Func<TFrom1, TFrom2, TFrom3, TFrom4, TFrom5, TTo> adapter)
            where TTo : class
            where TFrom1 : class
            where TFrom2 : class
            where TFrom3 : class
            where TFrom4 : class
            where TFrom5 : class
        {
            return VerifiedThatRequiredSignatureIsMatched(adapter);
        }

        public static Delegate FromFunc<TFrom1, TFrom2, TFrom3, TFrom4, TFrom5, TFrom6, TTo>(Func<TFrom1, TFrom2, TFrom3, TFrom4, TFrom5, TFrom6, TTo> adapter)
            where TTo : class
            where TFrom1 : class
            where TFrom2 : class
            where TFrom3 : class
            where TFrom4 : class
            where TFrom5 : class
            where TFrom6 : class
        {
            return VerifiedThatRequiredSignatureIsMatched(adapter);
        }

    }
}
